package com.application.room.pojo;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

import org.apache.mina.core.buffer.IoBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.application.actor.pojo.Actor;
import com.application.room.manage.RoomManage;
import com.core.action.ActionConstants;
import com.core.utils.Constants;
import com.core.utils.GameUtils;
import com.core.utils.PushDataUtils;
import com.core.utils.StringUtil;

public class Room {
	private static final Logger log = LoggerFactory.getLogger(Room.class);
	public int roomId;

	public int mode;
	public int map;
	public int minlv;
	public int maxlv;
	public byte status;
	public String name;
	public String psd;
	public int creater;
	public boolean lock = false;
	public boolean hasPsd = false;
	int maxUserNo = 8;
	public RoomStatus RS;

	public Room(Actor a, int roomId, String roomName, String roomPsd, int mode,
			int map, int minlv, int maxlv) {

		this.roomId = roomId;
		this.creater = a.getId();
		this.mode = mode;
		this.map = map;
		this.minlv = minlv;
		this.maxlv = maxlv;
		this.name = roomName;
		this.psd = roomPsd;
		if (null != this.psd && this.psd.length() > 0) {
			hasPsd = true;
		}

		RS = new RoomStatus(maxUserNo);
		RS.userIn(a, a.getNickname(), a.getAvaterId() + "");
		a.roomId = roomId;
		a.chatmode = 1;

		IoBuffer sendBuffer = IoBuffer.allocate(128);
		sendBuffer.setAutoExpand(true);
		sendBuffer.putInt(ActionConstants.S2C_ACTION_CREATE_ROOM_OK);
		sendBuffer.putInt(roomId);
		sendBuffer.flip();
		sendBuffer = GameUtils.Serialize(sendBuffer);
		a.getSession().write(sendBuffer);

	}

	public void reEnterRoom(Actor a) {
		synchronized (RS) {
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_ENTER_ROOM);
			sendBuffer.putInt(roomId);
			StringUtil.putString(sendBuffer, name, Constants.DEFAULT_CHARSET);
			sendBuffer.putInt(map);
			sendBuffer.putInt(mode);
			sendBuffer.putInt(creater);
			sendBuffer.put((byte) RS.uids.size());
			for (int i = 0; i < RS.uids.size(); i++) {
				sendBuffer.putInt(RS.uids.get(i));
				sendBuffer.put(RS.sids.get(i));
				sendBuffer.put(RS.status.get(i));
				StringUtil.putString(sendBuffer, RS.icons.get(i),
						Constants.DEFAULT_CHARSET);
				StringUtil.putString(sendBuffer, RS.names.get(i),
						Constants.DEFAULT_CHARSET);
			}
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			a.getSession().write(sendBuffer);
		}
	}

	public boolean actorEnterRoom(Actor a) {
		synchronized (RS) {

			if (!RS.userIn(a, a.getNickname(), a.getAvaterId() + ""))
				return false;

			a.roomId = roomId;
			a.chatmode = 1;

			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_OTHERACTOR_ENTER_ROOM);
			sendBuffer.putInt(a.getId());
			sendBuffer.put(RS.getUserSeatId(a.getId()));
			StringUtil.putString(sendBuffer, "", Constants.DEFAULT_CHARSET);
			StringUtil.putString(sendBuffer, a.getNickname(),
					Constants.DEFAULT_CHARSET);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			set.remove(a);
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_OTHERACTOR_ENTER_ROOM);

			sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_ENTER_ROOM);
			sendBuffer.putInt(roomId);
			StringUtil.putString(sendBuffer, name, Constants.DEFAULT_CHARSET);
			sendBuffer.putInt(map);
			sendBuffer.putInt(mode);
			sendBuffer.putInt(creater);
			sendBuffer.put((byte) RS.uids.size());
			for (int i = 0; i < RS.uids.size(); i++) {
				sendBuffer.putInt(RS.uids.get(i));
				sendBuffer.put(RS.sids.get(i));
				sendBuffer.put(RS.status.get(i));
				StringUtil.putString(sendBuffer, RS.icons.get(i),
						Constants.DEFAULT_CHARSET);
				StringUtil.putString(sendBuffer, RS.names.get(i),
						Constants.DEFAULT_CHARSET);
			}
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			a.getSession().write(sendBuffer);
			return true;
		}

	}

	public void kikOutRoom() {

		synchronized (RS) {
			this.lock = true;
			for (Actor a : RS.actors.values()) {
				IoBuffer sendBuffer = IoBuffer.allocate(128);
				sendBuffer.setAutoExpand(true);
				sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_OUTOF_ROOM);
				sendBuffer.putInt(a.getId());
				sendBuffer.putInt(this.creater);
				sendBuffer.flip();
				sendBuffer = GameUtils.Serialize(sendBuffer);
				a.getSession().write(sendBuffer);
			}
			RS.actors.clear();
			RS.uids.clear();
			this.isEmpty = true;
		}

	}

	public boolean kickOutFromRoom(Actor createrUser, Actor a) {
		if (createrUser.getId() != this.creater) {
			return false;
		}
		if (lock)
			return false;
		synchronized (RS) {
			if (!RS.userOut(a.getId()))
				return false;

			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_KICK_FROM_ROOM);
			sendBuffer.putInt(a.getId());
			StringUtil.putString(sendBuffer, a.getNickname(),
					Constants.DEFAULT_CHARSET);
			StringUtil.putString(sendBuffer, createrUser.getNickname(),
					Constants.DEFAULT_CHARSET);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_ACTOR_KICK_FROM_ROOM);


		}
		return true;

	}

	public void userOutofRoom(Actor a) {
//		if (lock)
//			return;
		synchronized (RS) {
			if (!RS.userOut(a.getId()))
				return;

			if ((a.getId() == this.creater) && RS.getUids().size() != 0) {
				if (RS.getUids().size() > 1) {
					Random random1 = new Random();
					this.creater = (Integer) RS.getUids().get(
							Math.abs(random1.nextInt()) % RS.getUids().size());
				} else {
					this.creater = (Integer) RS.getUids().get(0);
				}
			}

			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_OUTOF_ROOM);
			sendBuffer.putInt(a.getId());
			sendBuffer.putInt(this.creater);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			set.add(a);
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_ACTOR_OUTOF_ROOM);

		}

	}

	public void offline(Actor a) {
	 
		userOutofRoom(a);

	}

	public int getUserNumber() {
		synchronized (RS) {
			return RS.getUserNumber();
		}
	}

	public boolean userChangeSeat(Actor a, int seatid) {
		if (lock)
			return false;
		synchronized (RS) {
			if (!RS.userChangeSeat(a.getId(), (byte) seatid))
				return false;
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_CHANGE_SITE);
			sendBuffer.putInt(a.getId());
			sendBuffer.put((byte) seatid);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_ACTOR_OUTOF_ROOM);
			return true;
		}

	}

	public boolean userReady(Actor a) {
		if (lock)
			return false;
		synchronized (RS) {
			if (!RS.userReady(a.getId()))
				return false;
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_READY);
			sendBuffer.putInt(a.getId());
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_ACTOR_OUTOF_ROOM);
		}
		return true;

	}

	public boolean userAbort(Actor a) {
		if (lock)
			return false;
		synchronized (RS) {
			if (!RS.userAbort(a.getId()))
				return false;
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_ACTOR_ABORT);
			sendBuffer.putInt(a.getId());
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_ACTOR_ABORT);
		}
		return true;

	}

	String result = "";
	long roomApplyTime;
	public boolean isEmpty = false;

	public void reset() {
		status = 0;
		lock = false;
		RS.reset();
		result = "";
	}

	public void checkRoom() {
		synchronized (RS) {
			if (!lock) {
				if (RS.roomIsReady(mode)) {
					lock = true;
					RoomManage.roomChange(roomId, RoomManage.CHANGE_ROOM);
					sendLockRoomInfo();
					status = 0;
				}

			}
			if (RS.roomIsEmpty()) {
				// destroy self
				lock = true;
				isEmpty = true;
			}
			if (!lock)
				return;
			if (isEmpty)
				return;
			switch (status) {
			case 0:
				applyRacingRoom();
				status = 1;
				break;
			case 1:
				if (result.equals("ok")) {
					sendGameStart();
					status = 2;
					break;
				} else if (result.equals("error")) {
					stopJoinGame();
					break;
				}

				break;
			case 2:
				if (System.currentTimeMillis() - roomApplyTime > 550000) {
					clearRoom();
					log
							.info("<error:>cannot receive room info from game server stop ai room id at "
									+ this.roomId);
					break;
				}

				// //tb.status=0;
				break;
			}

		}
	}

	private void sendLockRoomInfo() {
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_LOCK_ROOM);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_LOCK_ROOM);
		 
	}
	
	private void sendGameStart() {
		IoBuffer sendBuffer = IoBuffer.allocate(128);
		sendBuffer.setAutoExpand(true);
		sendBuffer.putInt(ActionConstants.S2C_ACTION_GAME_START);
		sendBuffer.putInt(this.roomId);
		sendBuffer.flip();
		sendBuffer = GameUtils.Serialize(sendBuffer);
		Set<Actor> set = new HashSet<Actor>();
		set.addAll(RS.actors.values());
		PushDataUtils.push(sendBuffer, set,
				ActionConstants.S2C_ACTION_GAME_START);
	}

	public void applyRacingRoom() {
		// talker.applyCreateRacingRoom("192.168.1.3", this.roomId);

		RoomManage.applyGameStart(this.roomId);
	}

	public void roomCreated() {
		roomApplyTime = System.currentTimeMillis();

		result = "ok";
	}

	public void roomCraeateFailed() {

		result = "error";
	}

	private void clearRoom() {

		RoomManage.clearRoom(this.roomId);
	}

	private void stopJoinGame() {
		synchronized (RS) {
			IoBuffer sendBuffer = IoBuffer.allocate(128);
			sendBuffer.setAutoExpand(true);
			sendBuffer.putInt(ActionConstants.S2C_ACTION_STOP_JOIN_GAME);
			sendBuffer.flip();
			sendBuffer = GameUtils.Serialize(sendBuffer);
			Set<Actor> set = new HashSet<Actor>();
			set.addAll(RS.actors.values());
			PushDataUtils.push(sendBuffer, set,
					ActionConstants.S2C_ACTION_STOP_JOIN_GAME);
			reset();
		}
	}

}
